package com.wrupple.muba.catalogs.client.widgets.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.TakesValue;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.wrupple.muba.catalogs.client.activity.process.FilterSelectionProcess;
import com.wrupple.muba.catalogs.client.activity.process.impl.ForeignKeyFilterSelectionProcessImpl.FilterSelection;
import com.wrupple.muba.catalogs.client.events.FilterValueChangeEvent;
import com.wrupple.muba.catalogs.client.events.NewFilterSelectionEvent;
import com.wrupple.muba.catalogs.client.events.NewFilterSelectionEventHandler;
import com.wrupple.muba.catalogs.client.view.FilterToolbar;
import com.wrupple.muba.common.domain.FilterCriteria;
import com.wrupple.muba.common.domain.FilterData;

/**
 * There will never be a posibility greater than 0 of anyone ever needing
 * another implementation of the FilterView, people might, however, implement
 * FilterView differently, but the awesomeness of this implementation will never
 * be surpassed.
 * 
 * @author japi (tempt me not)
 * 
 */
public class FilterToolbarImpl extends Composite implements FilterToolbar {


	private static AwesomeFilterViewUiBinder uiBinder = GWT.create(AwesomeFilterViewUiBinder.class);

	interface AwesomeFilterViewUiBinder extends UiBinder<Widget, FilterToolbarImpl> {
	}

	public interface FieldFilter extends TakesValue<FilterSelection>, IsWidget, HasClickHandlers{
		
	}
	
	class RemoveCriteriaHandler implements ClickHandler {

		private FieldFilter widget;

		public RemoveCriteriaHandler(FieldFilter widget) {
			this.widget=widget;
		}

		@Override
		public void onClick(ClickEvent event) {
			container.remove(widget);
			fireChangeEvent();
		}
		
	}
	
	class ToolbarNewFilterSelectionEventHandler implements NewFilterSelectionEventHandler{

		@Override
		public void onNewFilterSelected(NewFilterSelectionEvent e) {
			FilterSelection newFilter = e.getFilterSelection();
			addCriteria(newFilter);
			fireChangeEvent();
		}
		
	}
	

	@UiField
	FlowPanel container;

	private Provider<FieldFilter> widgetProvider;
	private FilterData originalValue;

	private EventBus eventBus;


	@Inject
	public FilterToolbarImpl(Provider<FilterSelectionProcess> processProvider, Provider<FieldFilter> widgetProvider) {
		initWidget(uiBinder.createAndBindUi(this));
		this.widgetProvider=widgetProvider;
	}
	
	
	@Override
	public void addCriteria(FilterSelection result) {
		FieldFilter widget = widgetProvider.get();
		widget.addClickHandler(new RemoveCriteriaHandler(widget));
		widget.setValue(result);
		container.add(widget);
	}

	@Override
	public FilterData getValue() {
		if(originalValue==null){
		}else{
			Map<String, List<FilterCriteria>> filters = extractCurrentFilters();
			originalValue.setFilters(filters);
		}
		return originalValue;
	}


	@Override
	public void setValue(FilterData value) {
		this.originalValue=value;
		if(originalValue==null){
			originalValue = new FilterData();
		}
		clearWidgetsAndDisplayNewValue(originalValue.getFilters());
		fireChangeEvent();
	}


	public void fireChangeEvent() {
		FilterData newValue = getValue();
		ValueChangeEvent.fire(this, newValue);
		eventBus.fireEvent(new FilterValueChangeEvent(newValue));
	}



	
	public void finish(ClickEvent e) {
		FilterData data = getValue();
		ValueChangeEvent.fire(this, data);
	}

	@Override
	public void setValue(FilterData value, boolean fireEvents) {
		setValue(value);
		if (fireEvents) {
			ValueChangeEvent.fire(this, getValue());
		}
	}

	@Override
	public HandlerRegistration addValueChangeHandler(
			ValueChangeHandler<FilterData> handler) {
		return this.addHandler(handler, ValueChangeEvent.getType());
	}


	@Override
	public HandlerRegistration addResizeHandler(ResizeHandler handler) {
		return addHandler(handler, ResizeEvent.getType());
	}

	@Override
	public Direction getDirection() {
		return Direction.NORTH;
	}

	@Override
	public int getSize() {
		return 25;
	}


	@Override
	public void initialize(
			com.wrupple.muba.common.shared.State.ProcessManager pm,EventBus bus) {
		this.eventBus = bus;
		bus.addHandler(NewFilterSelectionEvent.TYPE, new ToolbarNewFilterSelectionEventHandler());
	}

	private void clearWidgetsAndDisplayNewValue(
			Map<String, List<FilterCriteria>> filters) {
		container.clear();
		Set<String> fields = filters.keySet();
		FilterSelection filter;
		List<FilterCriteria> criters;
		for(String field: fields){
			filter = new FilterSelection();
			criters = filters.get(field);
			filter.setCriters(criters);
			filter.setFieldid(field);
		}		
	}
	
	private Map<String, List<FilterCriteria>> extractCurrentFilters() {
		TakesValue<FilterSelection> widget;
		FilterSelection e ;
		String fieldid;
		List<FilterCriteria> criters;
		Map<String, List<FilterCriteria>> regreso = new HashMap<String, List<FilterCriteria>>();
		for(Widget w:container){
			widget=(TakesValue<FilterSelection>) w;
			e = widget.getValue();
			fieldid=e.getFieldid();
			criters=regreso.get(fieldid);
			if(criters==null){
				criters=new ArrayList<FilterCriteria>();
				regreso.put(fieldid, criters);
			}
			criters.addAll(e.getCriters());
		}
		
		return regreso;
	}

}
